package cmpe451.group7.ourcity.service.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cmpe451.group7.ourcity.dao.PlaceDAO;
import cmpe451.group7.ourcity.dao.TagSimilarityDAO;
import cmpe451.group7.ourcity.entity.Place;
import cmpe451.group7.ourcity.entity.Tag;
import cmpe451.group7.ourcity.entity.TagSimilarity;
import cmpe451.group7.ourcity.recommendation.SimilarityFinder;
import cmpe451.group7.ourcity.service.SearchService;

@Service("searchService")
public class SearchServiceImpl implements SearchService, Serializable {

	private static final long serialVersionUID = 1L;

	@Autowired
	private TagSimilarityDAO tagSimilarityDAO;

	@Autowired
	private PlaceDAO placeDAO;

	@Override
	@Transactional
	public List<Tag> getRelatedTags(List<Tag> tags) {
		if (CollectionUtils.isEmpty(tags))
			return null;

		// First make sure that database is filled with similar tags
		getTagSimilarities(tags);

		return tagSimilarityDAO.getAllSimilarTags(tags);
	}

	@Override
	@Transactional
	public List<TagSimilarity> getTagSimilarities(List<Tag> tags) {
		// first check the input
		List<TagSimilarity> results = new ArrayList<TagSimilarity>();
		if (CollectionUtils.isEmpty(tags)) {
			return results;
		}

		// Check for the database for the related keywords
		for (Tag t : tags) {
			List<TagSimilarity> relatedTags = getRelatedTags(t);
			if (CollectionUtils.isNotEmpty(relatedTags))
				results.addAll(relatedTags);
		}

		return results;
	}

	@Override
	@Transactional
	public List<Place> getRelatedPlaces(List<Tag> tags) {
		List<Place> relatedPlaces = new ArrayList<Place>();
		if (CollectionUtils.isEmpty(tags))
			return relatedPlaces;

		List<Place> searchPlaces = placeDAO.getRelatedPlaces(tags);
		if (CollectionUtils.isNotEmpty(searchPlaces))
			relatedPlaces.addAll(searchPlaces);

		return relatedPlaces;
	}

	@Transactional
	private List<TagSimilarity> getRelatedTags(Tag tag) {
		// if this is a user generated tag, skip it
		// TODO: maybe this could be improved
		if (StringUtils.isEmpty(tag.getmID()))
			return null;

		// if we already retrieved this tag's similar tags, skip
		boolean hasSimilarity = tagSimilarityDAO.hasSimilarity(tag);
		if (hasSimilarity)
			return tagSimilarityDAO.findByMID1(tag.getmID());

		// find the similar tags
		List<TagSimilarity> similarTags = SimilarityFinder.findSimilarTags(tag
				.getTagName());

		// first add the same object

		// add the similar tags to the database
		if (CollectionUtils.isNotEmpty(similarTags)) {
			for (TagSimilarity ts : similarTags) {
				ts.setTag1_mID(tag.getmID());
				tagSimilarityDAO.save(ts);
			}
		}

		TagSimilarity same = new TagSimilarity(tag.getmID(), tag.getmID(),
				TagSimilarity.DEFAULT_SIMILARITY_VALUE);
		tagSimilarityDAO.save(same);
		similarTags.add(0, same);

		return similarTags;
	}

	@Override
	@Transactional
	public List<Place> detailedSearch(String placeName, String country,
			String city, Date fromDate, Date toDate, List<Tag> tags,
			double ne_lat, double ne_lng, double sw_lat, double sw_lng) {

		getRelatedTags(tags);
		return placeDAO.findByRestrictions(placeName, country, city, fromDate,
				toDate, tags, ne_lat, ne_lng, sw_lat, sw_lng);
	}

	@Override
	public List<Place> detailedSearch(String placeName, String country,
			String city, Date fromDate, Date toDate, List<Tag> selectedTags) {
		return detailedSearch(placeName, country, city, fromDate, toDate,
				selectedTags, 0, 0, 0, 0);
	}

}
